/*
 * Peripheral Simulator (PSim)
 *
 * Copyright (c) 2008 Avadh Patel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*************** ETH/TIK specific 

Changes/additions by M. Gries, A.Romer:
---------------------------------------
Computer Engineering and Communication Networks Lab (TIK)
Swiss Federal Institute of Technology (ETH) Zurich, Switzerland

- DRAM models for SDRAM and DRDRAM 
- integrated memory controller model (no FSB) with open-page counters,
  simple address mapping, and some pipelining facilities
- the cache miss handlers have been modified in order to cope
  with the new signature of mem_access_latency()
- new options concerning the DRAM models and the memory controller:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-memctrl:addr    <string>         #  interleaved # memory controller address map {linear,interleaved}
-memctrl:pipe    <true|false>     #        false # memory controller control signal pipeline enabled if set
-memctrl:page_act <string>        #         open # memory controller page activation policy {open,closed}
-mem:type        <string>         #          STD # memory type {SDRAM|DRDRAM|STD}

-mem:prt_access  <string>         #       <null> # print memory accesses to specified file
-mem:prt_detail  <true|false>     #        false # show memory access details for SDRAM and DRDRAM if set
-mem:show_stats  <true|false>     #        false # show memory access stats for SDRAM and DRDRAM if set

-cpu:ratio       <float>          #       1.0000 # ratio between CPU and memory bus speed (SDRAM @100MHz or @133MHz, 
                                                 # RDRAM @400MHz, no effect on STD type)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

- addition of some dozens of statistical counters for hit/miss analysis
  within DRAM rows and banks 


 IN NO EVENT SHALL THE TIK OR THE ETH ZURICH BE LIABLE TO ANY PARTY
 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 THE TIK OR THE ETH ZURICH HAVE BEEN ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 THE TIK AND THE ETH ZURICH SPECIFICALLY DISCLAIM ANY WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND TIK AND THE ETH ZURICH 
 HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 ENHANCEMENTS, OR MODIFICATIONS.

***********/
#include <stdio.h>

#include <config.h>
#include <cpu.h>
#include <cpu-defs.h>
#include <cpu-all.h>

#include <psim.h>
#include <psim_lib.h>

#include "ram.h"

/* SDRAM system: PC100/PC133 2-2-2 DIMM timing according to 
   PC SDRAM Specification, Rev. 1.7, Intel Corp, Nov. 1999.

   64 bit DIMM consists of four 16x organized 256 Mbit SDRAMs, 128 MByte of main memory in total.*/

#define  SD_DATA_BASE  0x4000000 /* Size of textsegment :  64 Mbyte */
#define  SD_STACK_BASE 0x80000000 /* total size of memory: 1024 Mbyte */
#define  SD_BANK_SIZE  0x10000000 /* size of a bank      :  256 Mbyte */
#define  SD_ROW_SIZE 0x1000      /* size of a row       :   4 Kbyte */
#define  SD_NUM_BYTE_MEM  8      /* [byte]; memory delivers in one clock cycle (DIMM width) */
#define  SD_T_CAS 4 /* delay after read command until data ready */
#define  SD_T_WAR 2 /* write after read time: for avoiding data contention */
#define  SD_T_PRE 2 /* precharge time */
#define  SD_T_ACT 2 /* RAS to CAS delay: activation time */
#define  SD_T_DPL 2 /* Data in to Precharge time */
/* the settings above must be changed if another memory is used */
#define  SD_DYNAMIC_SIZE (SD_STACK_BASE - SD_DATA_BASE)      /* size of heap and stack */
#define  SD_NUM_BANKS (SD_STACK_BASE/SD_BANK_SIZE)           /* number of banks */
#define  SD_NUM_ROWS (SD_BANK_SIZE/SD_ROW_SIZE)              /* number of rows per bank */
/*delays until data is ready/written to the memory for the SDRAM*/
#define  SD_T_READ_READ_SROW    SD_T_CAS                     /* RAR, row hit, current bank  */
#define  SD_T_READ_WRITE_SROW   SD_T_CAS                     /* RAW, row hit, current bank  */
#define  SD_T_WRITE_READ_SROW   (SD_T_WAR-1)                 /* WAR, row hit, current bank  */
#define  SD_T_WRITE_WRITE_SROW  0                            /* WAW, row hit, current bank  */
#define  SD_T_READ_READ_SBANK   (SD_T_PRE+SD_T_ACT+SD_T_CAS) /* RAR, row miss, current bank */
#define  SD_T_READ_WRITE_SBANK  (SD_T_PRE+SD_T_ACT+SD_T_CAS+(SD_T_DPL-1)) /* RAW, row miss, current bank */
#define  SD_T_WRITE_READ_SBANK  (SD_T_PRE+SD_T_ACT)          /* WAR, row miss, current bank */
#define  SD_T_WRITE_WRITE_SBANK (SD_T_PRE+SD_T_ACT+(SD_T_DPL-1)) /* WAW, row miss, current bank */
#define  SD_T_READ_READ_OBANK   (SD_T_PRE+SD_T_ACT+SD_T_CAS) /* RAR, row miss, another bank */
#define  SD_T_READ_WRITE_OBANK  (SD_T_PRE+SD_T_ACT+SD_T_CAS) /* RAW, row miss, another bank */
#define  SD_T_WRITE_READ_OBANK  (SD_T_PRE+SD_T_ACT)          /* WAR, row miss, another bank */
#define  SD_T_WRITE_WRITE_OBANK (SD_T_PRE+SD_T_ACT)          /* WAW, row miss, another bank */
/* best-case latencies (due to overlap / row hits in another bank) */
#define  SD_BEST_T_READ_READ_SROW    0                       /* RAR, row hit, current bank  */
#define  SD_BEST_T_READ_READ_SBANK   (SD_T_ACT+SD_T_CAS)     /* RAR, row miss, current bank */
#define  SD_BEST_T_WRITE_READ_SBANK  (SD_T_ACT)              /* WAR, row miss, current bank */
#define  SD_BEST_T_READ_READ_OBANK   0                       /* RAR, row miss/hit, another bank */
#define  SD_BEST_T_READ_WRITE_OBANK  SD_T_CAS                /* RAW, row miss/hit, another bank */
#define  SD_BEST_T_WRITE_READ_OBANK  (SD_T_WAR -1)           /* WAR, row miss/hit, another bank */
#define  SD_BEST_T_WRITE_WRITE_OBANK 0                       /* WAW, row miss/hit, another bank */

/* DRDRAM system: 16 bit channel, four chips (single RIMM), 128 MByte of main memory in total.
   Timing: Rambus Inc, Direct RDRAM, preliminary information, 256/288Mbit: 40-800 timing */

#define  DR_DATA_BASE  0x4000000 /* Size of textsegment :  64 Mbyte */
#define  DR_STACK_BASE 0x8000000 /* total size of memory: 128 Mbyte */
#define  DR_BANK_SIZE  0x100000  /* size of a bank      :   1 Mbyte */
#define  DR_ROW_SIZE 0x800       /* size of a row       :   2 Kbyte */
#define  DR_NUM_BYTE_MEM  16     /* data packet capacity:  16 byte  */
#define  DR_NUM_DEVS 4   /* number of devices along channel */ 
#define  DR_BANK_SAMP 16 /* 16 banks are together in one group in each device: bank 15 and 16 have no shared SAMPs */
#define  DR_T_PACKET 4   /* number of cycles (in 400 MHz) the memory needs to deliver a data packet */ 
#define  DR_T_RCD 7  /* RAS to CAS delay */
#define  DR_T_CAC 8  /* read access delay: number of cylces from read to data  (trailing to leading edge of packet!) */
#define  DR_T_CWD 6  /* Write delay: number of cylces from write to write data (trailing to leading edge of packet!) */
#define  DR_T_RP  8  /* row precharge delay */
#define  DR_T_RTR 8  /* retire delay*/
#define  DR_T_RDP 4  /* min delay from read to precharge in cycles */
#define  DR_T_PP  8  /* precharge to precharge time to any bank in the same device */ 
#define  DR_T_RAS 20 /* minimal row active time */
/*the settings above need to be changed if the memory is altered*/
#define  DR_DYNAMIC_SIZE (DR_STACK_BASE - DR_DATA_BASE) /* size of the heap and stack at most: 64 Mbyte */
#define  DR_NUM_BANKS (DR_STACK_BASE/DR_BANK_SIZE)      /* number of banks        : 128 */
#define  DR_NUM_ROWS (DR_BANK_SIZE/DR_ROW_SIZE)         /* number of rows per bank: 512 */
#define  DR_T_OWR (DR_T_CWD + DR_T_PACKET - DR_T_RTR)   /* overlap after write retire   */
#define  DR_T_HELP (DR_T_CAC+DR_T_PACKET-DR_T_RDP+DR_T_PACKET) /* used for read after read with precharge */
/*delays until data is ready/written to the memory for the DRDRAM*/
#define  DR_T_READ_READ_SROW    (DR_T_CAC + DR_T_PACKET) /* RAR, row hit, current bank */
#define  DR_T_READ_WRITE_SROW   (DR_T_CAC + DR_T_PACKET) /* RAW, row hit, current bank */
#define  DR_T_WRITE_READ_SROW   (DR_T_CWD + DR_T_PACKET) /* WAR, row hit, current bank */
#define  DR_T_WRITE_WRITE_SROW  (DR_T_CWD + DR_T_PACKET) /* WAW, row hit, current bank */
#define  DR_T_READ_READ_SBANK   (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAR, row miss, current bank */
#define  DR_T_READ_WRITE_SBANK  (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAW, row miss, current bank */
#define  DR_T_WRITE_READ_SBANK  (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, current bank */
#define  DR_T_WRITE_WRITE_SBANK (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, current bank */
#define  DR_T_READ_READ_OBANK   (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAR, row miss, another bank */
#define  DR_T_READ_WRITE_OBANK  (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAW, row miss, another bank */
#define  DR_T_WRITE_READ_OBANK  (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, another bank */
#define  DR_T_WRITE_WRITE_OBANK (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, another bank */
/* best-case latencies (due to overlap / row hits in another bank) */
#define  DR_BEST_T_READ_READ_SROW    0                               /* RAR, row hit, current bank */
#define  DR_BEST_T_READ_WRITE_SROW   (DR_T_CAC+DR_T_PACKET-DR_T_OWR) /* RAW, row hit, current bank */
#define  DR_BEST_T_WRITE_READ_SROW   0                               /* WAR, row hit, current bank */
#define  DR_BEST_T_WRITE_WRITE_SROW  (DR_T_CWD+DR_T_PACKET-DR_T_OWR) /* WAR, row hit, current bank */
#define  DR_BEST_T_READ_READ_SBANK   (DR_T_RCD + DR_T_CAC)                            /* RAR, row miss, current bank */
#define  DR_BEST_T_READ_WRITE_SBANK  (DR_T_RP-DR_T_OWR+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAW, row miss, current bank */
#define  DR_BEST_T_WRITE_READ_SBANK  (DR_T_RCD+DR_T_CWD)                              /* WAR, row miss, current bank */
#define  DR_BEST_T_WRITE_WRITE_SBANK (DR_T_RP-DR_T_OWR+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAW, row miss, current bank */
#define  DR_BEST_T_READ_READ_OBANK   0                   /* RAR, row miss/hit, another bank   */
#define  DR_BEST_T_READ_WRITE_OBANK  (DR_T_PACKET+DR_T_CAC-DR_T_OWR) /* RAW, row miss/hit, another bank */
#define  DR_BEST_T_WRITE_READ_OBANK  0                   /* WAR, row miss/hit, another bank   */
#define  DR_BEST_T_WRITE_WRITE_OBANK 0                   /* WAW, row miss/hit, another bank   */
#define  DR_BEST_T_READ_WRITE_ODEV   (DR_T_CAC-DR_T_CWD) /* RAW, row miss/hit, another device */ 

//#define MAX(a, b)    (((a) < (b)) ? (b) : (a))

/* virtual memory segment limits */
#define MD_TEXT_BASE		0x00400000
#define MD_DATA_BASE		0x10000000
#define MD_STACK_BASE 		0x7fffc000

//Define NULL - To fix the issue of segfault
#ifdef NULL
#undef NULL
#endif

#define NULL (void*)(0)

/* bank-wise active row (open-page) counter */
static int active_row[MAX(SD_NUM_BANKS,DR_NUM_BANKS)];

//enum {
//  FALSE = 0,
//  TRUE
//};

enum {
  never_accessed=Write+1
} ;
static enum mem_cmd last_cmd = never_accessed;           /* initialized as never accessed */
static int last_bank = MAX(SD_NUM_BANKS,DR_NUM_BANKS)+1; /* initialized as never accessed: top bank + 2 */
static int last_row  = MAX(SD_NUM_ROWS,DR_NUM_ROWS);     /* initialized as never accessed: top row + 1  */
static int last_dev  = DR_NUM_DEVS+1; 
static tick_t busy_until = 0; /* first CPU cycle in which data bus is no longer busy */
static int precharge = 0;

/* memory access statistics */
static counter_t same_row_read_access=0;
static counter_t srr_after_read=0;
static counter_t srr_after_write=0;
static counter_t same_row_write_access=0;
static counter_t srw_after_read=0;
static counter_t srw_after_write=0;

static counter_t same_bank_read_access=0;
static counter_t sbr_after_read=0;
static counter_t sbr_after_write=0;
static counter_t same_bank_write_access=0;
static counter_t sbw_after_read=0;
static counter_t sbw_after_write=0;

static counter_t other_bank_read_access_hit=0;
static counter_t obr_after_read_hit=0;
static counter_t obr_after_write_hit=0;
static counter_t other_bank_write_access_hit=0;
static counter_t obw_after_read_hit=0;
static counter_t obw_after_write_hit=0;
static counter_t other_bank_read_access_miss=0;
static counter_t obr_after_read_miss=0;
static counter_t obr_after_write_miss=0;
static counter_t other_bank_write_access_miss=0;
static counter_t obw_after_read_miss=0;
static counter_t obw_after_write_miss=0;

static counter_t total_access=0;

static counter_t adjacent_access=0;
static counter_t adjacent_read=0;
static counter_t adjacent_write=0;
static counter_t command_overlapping=0;
static counter_t best_case=0;
static counter_t in_between_case=0;
static counter_t worst_case=0;
static counter_t full_overlapping=0;
static counter_t partial_overlapping=0;

    /* debugging and trace generation; used for locality analysis */
/* md_addr_t old_physic_address;*/ /* address of preceding memory access */
/* tick_t old_now;*/ /* time of preceding memory access */

/*address map type of memory controller*/
static char *memctrladdr_type = "interleaved";

/*memory DRAM type*/
static char *mem_type = "SDRAM";

/*page activation policy*/
static char *mem_actpolicy="open";

/*memory controller pipelining of control signals*/
static int memctrlpipe_enable = FALSE;

/*Memory Bus Width*/
static int mem_bus_width = 8; //Width in bytes

/*Memory Latency*/
static int mem_lat[] = {
  10,	/*First chunk latency*/
  8,	/*Inter chunk latency*/
};

/*ratio between CPU speed and memory bus speed*/
static float cpu_ratio=1.0;

/*memory access output file*/
static char *mem_access_output=NULL;
FILE *mem_accessfd=NULL;

/*for memory stats*/
static int mem_show_stats = FALSE;
static int mem_access_details = FALSE;

void register_ram_stats()
{
  struct stat_sdb_t* sdb = sim_get_stat_db();

  if (mem_show_stats && strcmp(mem_type,"STD"))
    {
      stat_reg_counter(sdb, "mem.total_access", "total number of memory accesses",
                   &total_access, /* initial value */0, /* format */NULL);

      if (!strcmp(mem_type,"DRDRAM"))
	{
	  stat_reg_counter(sdb, "mem.adjacent_bank_access","access to an adjacent bank of the DRDRAM",
			   &adjacent_access,0,NULL);
	  stat_reg_counter(sdb, "mem.adjacent_read","read access to an adjacent bank of the DRDRAM",
			   &adjacent_read,0,NULL);
	  stat_reg_counter(sdb, "mem.adjacent_write","write access to an adjacent bank of the DRDRAM",
			   &adjacent_write,0,NULL);
	  stat_reg_formula(sdb, "mem.adjacent_access","adjacent_bank_access / total_access",
		   "mem.adjacent_bank_access / mem.total_access",/* format */NULL);
	}

      if (memctrlpipe_enable == TRUE) {
	stat_reg_counter(sdb, "mem.pipe_overlap","accesses which can make use of pipe",
			 &command_overlapping,0,NULL);
	stat_reg_formula(sdb, "mem.overlap_ratio","pipe_overlap / total_access",
			 "mem.pipe_overlap / mem.total_access",NULL);

	stat_reg_counter(sdb, "mem.full_overlap","access latency can be completely hidden",
			 &full_overlapping,0,NULL);
	stat_reg_formula(sdb, "mem.full_overlap_ratio","full_overlap / pipe_overlap",
			 "mem.full_overlap / mem.pipe_overlap",NULL);

	stat_reg_counter(sdb, "mem.partial_overlap","access latency can be partly hidden",
			 &partial_overlapping,0,NULL);
	stat_reg_formula(sdb, "mem.partial_overlap_ratio","partial_overlap / pipe_overlap",
			 "mem.partial_overlap / mem.pipe_overlap",NULL);
	
	stat_reg_counter(sdb, "mem.best_case","best case memory access latency",
			 &best_case,0,NULL);
	stat_reg_formula(sdb, "mem.best_case_ratio","best_case / total_access",
			 "mem.best_case / mem.total_access",NULL);
	
	stat_reg_counter(sdb, "mem.in_between_case","memory access latency is in between best and worst",
			 &in_between_case,0,NULL);   
	stat_reg_formula(sdb, "mem.in_between_case_ratio","in_between_case / total_access",
			 "mem.in_between_case / mem.total_access",NULL);
	
	stat_reg_counter(sdb, "mem.worst_case","worst case memory access latency",
			 &worst_case,0,NULL);
	stat_reg_formula(sdb, "mem.worst_case_ratio","worst_case / total_access",
			 "mem.worst_case / mem.total_access",NULL);
      }

      if (strcmp(mem_actpolicy, "closed")) { /* open page mode */
	stat_reg_counter(sdb, "mem.same_row_read_access", "memory read access to same row ",
			 &same_row_read_access, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.srr_after_read", "memory read access after read to same row ",
			 &srr_after_read, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.srr_after_write", "memory read access after write to same row ",
			 &srr_after_write, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.srr_access","same_row_read_access / total_access",
			 "mem.same_row_read_access / mem.total_access",/* format */NULL);
	
	stat_reg_counter(sdb, "mem.same_row_write_access", "memory write access to same row",
			 &same_row_write_access, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.srw_after_read", "memory write access after read to same row",
			 &srw_after_read, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.srw_after_write", "memory write access after write to same row",
			 &srw_after_write, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.srw_access","same_row_write_access / total_access",
			 "mem.same_row_write_access / mem.total_access",/* format */NULL);

	stat_reg_counter(sdb, "mem.same_bank_read_access", "memory read access to same bank",
			 &same_bank_read_access, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.sbr_after_read", "memory read access after read to same bank",
			 &sbr_after_read, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.sbr_after_write", "memory read access after write to same bank",
			 &sbr_after_write, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.sbr_access","same_bank_read_access / total_access",
			 "mem.same_bank_read_access / mem.total_access",/* format */NULL);

	stat_reg_counter(sdb, "mem.same_bank_write_access", "memory write access to same bank",
			 &same_bank_write_access, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.sbw_after_read", "memory write access after read to same bank",
			 &sbw_after_read, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.sbw_after_write", "memory write access after write to same bank",
			 &sbw_after_write, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.sbw_access","same_bank_write_access / total_access",
			 "mem.same_bank_write_access / mem.total_access",/* format */NULL);
	
	stat_reg_counter(sdb, "mem.other_bank_read_access_hit", "memory read access to other bank, hit",
			 &other_bank_read_access_hit, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obr_after_read_hit", "memory read access after read to other bank, hit",
			 &obr_after_read_hit, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obr_after_write_hit", "memory read access after write to other bank, hit",
			 &obr_after_write_hit, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.obr_access_hit","other_bank_read_access_hit / total_access",
			 "mem.other_bank_read_access_hit / mem.total_access",/* format */NULL);
	
	stat_reg_counter(sdb, "mem.other_bank_write_access_hit", "memory write access to other bank, hit",
			 &other_bank_write_access_hit, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obw_after_read_hit", "memory write access after read to other bank, hit",
			 &obw_after_read_hit, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obw_after_write_hit", "memory write access after write to other bank, hit",
			 &obw_after_write_hit, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.obw_access_hit","other_bank_write_access_hit / total_access",
			 "mem.other_bank_write_access_hit / mem.total_access",/* format */NULL);
	
	stat_reg_counter(sdb, "mem.other_bank_read_access_miss", "memory read access to other bank, miss",
			 &other_bank_read_access_miss, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obr_after_read_miss", "memory read access after read to other bank, miss",
			 &obr_after_read_miss, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obr_after_write_miss", "memory read access after write to other bank, miss",
			 &obr_after_write_miss, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.obr_access_miss","other_bank_read_access_miss / total_access",
			 "mem.other_bank_read_access_miss / mem.total_access",/* format */NULL);

	stat_reg_counter(sdb, "mem.other_bank_write_access_miss", "memory write access to other bank, miss",
			 &other_bank_write_access_miss, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obw_after_read_miss", "memory write access after read to other bank, miss",
			 &obw_after_read_miss, /* initial value */0, /* format */NULL);
	stat_reg_counter(sdb, "mem.obw_after_write_miss", "memory write access after write to other bank, miss",
			 &obw_after_write_miss, /* initial value */0, /* format */NULL);
	stat_reg_formula(sdb, "mem.obw_access_miss","other_bank_write_access_miss / total_access",
			 "mem.other_bank_write_access_miss / mem.total_access",/* format */NULL);
      }

    }
}  

void init_ram()
{
//  mem_access_output = "mem_output.log";
//  mem_accessfd = fopen(mem_access_output, "w+");
//  mem_show_stats = TRUE;
//  mem_access_details = TRUE;
   mem_access_output = NULL;
   mem_accessfd = NULL;
   mem_show_stats = TRUE;
   mem_access_details = FALSE;
  register_ram_stats();
}

/****** DRDRAM specific: shared sense amplifiers ******/
/* precharges the adjacent banks and returns the number of them (1 or 2)*/

int /*number of precharged banks*/
precharge_banks_around(int bank)/*access to bank */
{
int temp;

temp=bank%DR_BANK_SAMP;

if (temp == 0) /*bank 0, 16,32 ....*/
  {
    if (active_row[bank+1]!=DR_NUM_ROWS)
      {
	precharge++;
	active_row[bank+1]=DR_NUM_ROWS;
      }
  }
else
  {
    if (temp==DR_BANK_SAMP-1)/*banks 15,31 ...*/
      {
	if (active_row[bank-1]!=DR_NUM_ROWS)
	  {
	    precharge++;
	    active_row[bank-1]=DR_NUM_ROWS;
	  }	
      }
    else
      {
	if (active_row[bank-1]!=DR_NUM_ROWS)
	  {
	    precharge++;
	    active_row[bank-1]=DR_NUM_ROWS;
	  }
	if (active_row[bank+1]!=DR_NUM_ROWS)
	  {
	    precharge++;
	    active_row[bank+1]=DR_NUM_ROWS;
	  }
      }
  }
return precharge;
}

/****** calculate linear memory address ******/

//md_addr_t calcPhysAddr(md_addr_t baddr, char *mem_type) {
//
//  md_addr_t physic_address;
//
//  if (!strcmp(mem_type,"SDRAM"))
//    {
//      if (baddr < MD_DATA_BASE)    /*access to the text segment*/
//	{
//	  physic_address = baddr - MD_TEXT_BASE;
//	  if (physic_address > (SD_DATA_BASE - 1))
//	    panic("Program size is greater than the text segment and therefore accesses the heap (see procedure calcPhysAddr() in sim-outorder.c)");
//	}
//      else
//	{ 
//	  if (((MD_STACK_BASE - regs.regs_R[MD_REG_SP]) + (ld_brk_point - MD_DATA_BASE))> SD_DYNAMIC_SIZE)
//	    panic("Stack and heap size together are greater than the physical memory simulated (see procedure calcPhysAddr() in sim-outorder.c)");
//	  if (baddr <= ld_brk_point ) /*access to the data segment*/
//	    physic_address = baddr - MD_DATA_BASE + SD_DATA_BASE;
//	  else /*access to the stack segment*/
//	    physic_address = baddr - MD_STACK_BASE + SD_STACK_BASE;
//	}
//    }
//  else if (!strcmp(mem_type,"DRDRAM"))/*DRDRAM*/ 
//    /*a closed bank has an activ_row number of DR_NUM_ROWS: highest +1*/
//    {
//      if (baddr < MD_DATA_BASE)    /*access to the text segment*/
//	{
//	  physic_address = baddr - MD_TEXT_BASE;
//	  if (physic_address > (DR_DATA_BASE - 1))
//	    panic("Program size is greater than the textsegment and therefore accesses the heap (see procedure calcPhysAddr() in sim-outorder.c)");
//	}
//      else
//	{ 
//	  if (((MD_STACK_BASE - regs.regs_R[MD_REG_SP]) + (ld_brk_point - MD_DATA_BASE))> DR_DYNAMIC_SIZE)
//	    panic("Stack and heap size together are greater than the physical memory simulated (see procedure calcPhysAddr() in sim-outorder.c)");
//	  if (baddr <= ld_brk_point) /*access to the data segment*/
//	    physic_address = baddr - MD_DATA_BASE + DR_DATA_BASE;
//	  else /*access to the stack segment*/
//	    {
//	      physic_address = baddr - MD_STACK_BASE + DR_STACK_BASE;
//	    }
//	}
//    }
//	// simple trace generation
//	//	fprintf(stderr,"%ld %10.0f \n ",physic_address - old_physic_address, (double)(now - old_now));
//       	//	fprintf(stderr,"%7.0f\n ", (double)(now - old_now));
//	//	fprintf(stderr,"%ld \n ",physic_address);
//	//	old_physic_address = physic_address;
//       	//      old_now = now;
//
//  return physic_address;
//}


/* ========================== "regular" function =================================== */
/*
 Copyright (c) 2000 Computer Engineering and Communication Networks Lab (TIK)
 Swiss Federal Institute of Technology (ETH) Zurich, Switzerland

 All rights reserved.
 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 software and its documentation for any purpose, provided that the above
 copyright notice and the following two paragraphs appear in all copies
 of this software.

 IN NO EVENT SHALL THE TIK OR THE ETH ZURICH BE LIABLE TO ANY PARTY
 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 THE TIK OR THE ETH ZURICH HAVE BEEN ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 THE TIK AND THE ETH ZURICH SPECIFICALLY DISCLAIM ANY WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND TIK AND THE ETH ZURICH 
 HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 ENHANCEMENTS, OR MODIFICATIONS.
*/

/* authors: Andreas Romer 4/99 - 7/99
            Matthias Gries 4/99 - 2/01


References: http://www.tik.ee.ethz.ch/ 
======================================
-> Publications http://www.tik.ee.ethz.ch/db/tik/publications/form_search_publications.php3


Matthias Gries: A Survey of Synchronous RAM Architectures.
TIK Report Nr. 71, Computer Engineering and Networks Lab (TIK), 
Swiss Federal Institute of Technology (ETH) Zurich, April, 1999

-> DRAM survey


Matthias Gries, Andreas Romer: Performance Evaluation of Recent 
DRAM Architectures for Embedded Systems.
TIK Report Nr. 82, Computer Engineering and Networks Lab (TIK), 
Swiss Federal Institute of Technology (ETH) Zurich, November, 1999.

-> description of the DRAM and controller models for SimpleScalar in the appendix
(note that the current software version additionally supports overlapping in 
 closed-page mode with slightly modified timing)


Matthias Gries: The Impact of Recent DRAM Architectures on Embedded Systems Performance.
Euromicro2000, Symposium on Digital Systems Design, IEEE Computer, Maastricht, Netherlands, 
Vol. 1, pages 282-289, September, 2000.

-> performance study with SimpleScalar


Matthias Gries: Modeling a Memory Subsystem with Petri Nets: a Case Study.
A. Yakovlev, L. Gomes, and L. Lavagno (Eds), Hardware Design and Petri Nets, 
Kluwer Academic, pages 291-310, March, 2000.

-> SDRAM + controller performance model as a high-level Petri net
*/



/* memory access latency: it is assumed that burst accesses do not 
   cross a page boundary, that is, there are aligned with pages */

unsigned int			/* latency of access [CPU cycles]*/
mem_access_latency(enum mem_cmd cmd,	/* access cmd, Read or Write */
	           md_addr_t baddr,	/* block address accessed */
		   int bsize,		/* block size accessed */
		   tick_t now)		/* time of access */
{
  

  int lat=0, temp, current_bank, current_row, current_device;

  md_addr_t physic_address; /* linear memory address to be accessed */
  enum mem_cmd current_cmd;

  int num_blocks=0;
  int corrected_overlap, /* overlap of consecutive accesses [CPU cycles] */ 
    overlap=0;           /* overlap of consecutive accesses [mem bus cycles] */
  int adjacent=0; /* 1 indicates that current bank is adjacent to the last accessed  one*/

  int chunks = (bsize + (mem_bus_width - 1)) / mem_bus_width; // burst length
  assert(chunks >0);	  	
//  physic_address = calcPhysAddr(baddr, mem_type);
  physic_address = baddr;

    /*
     * SDRAM DIMM
     *+--------------+             +------------+        +-----------+
     *|              | 0           |   Bank 0   |        |           |
     *|              |             |  32 Mbyte  |        | 8192 rows |
     *|    text      |             |            | -----> |   with    |
     *|              |             +------------+        |  4 Kbyte  |
     *|              |             |   Bank 1   |        |   each    |
     *+--------------+             |  32 Mbyte  |        |in one Bank|
     *| |            | 64  Mbyte   |            |        |           | 
     *| | data seg   | (DATA_BASE) +------------+        +-----------+
     *| v            |             |   Bank 2   |
     *|              |             |  32 Mbyte  |
     *+--------------+             |            |
     *|              | 96  Mbyte   +------------+
     *| ^            |             |   Bank 3   |
     *| | stack seg  |             | 32 Mbyte   |
     *| |            |             |            |
     *+--------------+             +------------+
     *                 128 Mbyte 
     *                 (STACK_BASE)
     *
     * mapping of the 2 Gb simulated memory to four 256 Mbit memory devices
     * with 16 DataPins each (=> 64 bit DIMM), equals 128 Mbyte physical memory
     * the SDRAM runs at 100 MHz and has 4 banks
     *
     *
     * DRDRAM CHANNEL
     *
     *+--------------+             +------------+        +-----------+
     *|              | 0           |  Bank  0   | ---->  |           |
     *|              |             |  1 Mbyte   |        | 512 rows  |
     *|    text      |             +------------+        |   with    |
     *|              |             |  Bank  1   |        |  2 Kbyte  |
     *|              |             |  2 Mbyte   |        |   each    |
     *+--------------+             +------------+        |in one Bank|
     *| |            | 64  Mbyte   |    :       |        |           | 
     *| | data seg   | (DATA_BASE) |    :       |        +-----------+
     *| v            |             |    :       |
     *|              |             +------------+
     *+--------------+             |  Bank 126  |
     *|              | 96  Mbyte   |  1 Mbyte   | 
     *| ^            |             +------------+
     *| | stack seg  |             |  Bank 127  |
     *| |            |             |  1 Mbyte   |
     *+--------------+             +------------+
     *                 128 Mbyte 
     *                 (STACK_BASE)
     *
     * mapping of the 2 Gb simulated memory to four 256 Mbit memory devices
     * with 16 DataPins each , equals 128 Mbyte physical memory
     * DRDRAM runs at 400 MHz, both edges used, channel has 128 banks
     * the module delivers 16 byte (128 bit) in 4 cycles (packet size)
     */

    if (!strcmp(mem_type,"SDRAM") && !strcmp(mem_actpolicy, "open"))
      {

        if (strcmp(memctrladdr_type,"interleaved"))/* i.e. mc_type is linear */
          {
            current_bank=physic_address/SD_BANK_SIZE;
            temp=physic_address-current_bank*SD_BANK_SIZE;/*address in bank*/
            current_row=temp/SD_ROW_SIZE;
          }
        else/* mc_type interleaved */
          /* This memory controller maps the addresses differently
           * depending on the row_size, every row is mapped to another
           * bank. Thus, the text segment uses half of every bank, the heap
           * the next quarter of each bank, and the stack the rest.
           */
          
          {
            num_blocks = physic_address/SD_ROW_SIZE; /* row number */
            current_bank=num_blocks%SD_NUM_BANKS; 
            current_row=num_blocks/SD_NUM_BANKS;
          }

        current_cmd = cmd;

        if (mem_access_output != NULL && mem_access_details == TRUE) 
          {
            fprintf(mem_accessfd,"       %09u  %4d   %3d\n",physic_address,current_row,current_bank);
          }
        else	    
          {
            if (mem_access_output!=NULL)
              {
            fprintf(mem_accessfd,"\n");
              }
          }
        total_access++;

        if (memctrlpipe_enable == TRUE) 
          {
            overlap=(int)(busy_until - now);
          }
        else overlap = 0;

        if (cpu_ratio < 1.0)
          {
            corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
          }
        else
          {
            corrected_overlap = (int) (overlap/cpu_ratio);
          }

        /*fprintf(stderr,"%10.0f %10.0f %4d %4d ",(double)busy_until, (double)now, overlap, corrected_overlap); debugging*/

        if (current_cmd == last_cmd)/*same command*/
          {
            if (current_bank == last_bank)/*same bank*/
              {
            if (current_row == last_row)/*same row*/
              {
                if (current_cmd == Read)
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    /*best case*/
                    if (corrected_overlap >= SD_T_CAS)
                      {
                    lat=SD_BEST_T_READ_READ_SROW;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_CAS-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else
                  {
                    /*worst case*/
                    lat = SD_T_READ_READ_SROW;
                    worst_case++;
                  }
                same_row_read_access++;
                srr_after_read++;
                  }
                else/*write*/
                  {/*no option case*/
                lat = SD_T_WRITE_WRITE_SROW;
                same_row_write_access++;
                srw_after_write++;
                worst_case++;
                  }
              }
            else /*other row in same bank*/   
              { 
                if (current_cmd == Read)
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    if (corrected_overlap >= SD_T_PRE)/*best case*/
                      {
                    lat = SD_BEST_T_READ_READ_SBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_READ_READ_SBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = SD_T_READ_READ_SBANK;
                    worst_case++;
                  }
                same_bank_read_access++;
                sbr_after_read++;
                  }
                else/*write*/
                  {/*no option case*/
                lat = SD_T_WRITE_WRITE_SBANK;
                same_bank_write_access++;
                sbw_after_write++;
                worst_case++;
                  }
              }
              }
            else /*other bank*/
              {
            if (current_cmd == Read)
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { 
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >= SD_T_CAS)/*best case*/
                      {
                    lat = SD_BEST_T_READ_READ_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_CAS-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*in between case*/
                  {
                    lat = SD_T_CAS;
                    in_between_case++;
                  }
                other_bank_read_access_hit++;
                obr_after_read_hit++;
                  }
                else/*row is not active*/
                  {
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >= SD_T_READ_READ_OBANK )/*best case*/
                      {
                    lat = SD_BEST_T_READ_READ_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_READ_READ_OBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = SD_T_READ_READ_OBANK;
                    worst_case++;
                  }
                other_bank_read_access_miss++;
                obr_after_read_miss++;
                  }
              }
            else/*write*/
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { /*best_case*/
                lat = SD_BEST_T_WRITE_WRITE_OBANK;
                best_case++;
                other_bank_write_access_hit++;
                obw_after_write_hit++;  
                  }
                else/*row is not active*/
                  {
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >=SD_T_WRITE_WRITE_OBANK)/*best case*/
                      {
                    lat = SD_BEST_T_WRITE_WRITE_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_WRITE_WRITE_OBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = SD_T_WRITE_WRITE_OBANK;
                    worst_case++;
                  }
                other_bank_write_access_miss++;
                obw_after_write_miss++;  

                  }
              }
              }
          }
        else /*current_cmd != last_cmd*/
          {
            if (current_bank == last_bank)/*same bank*/
              {
            if (current_row == last_row)/*same row*/
              {
                if (current_cmd == Read)
                  {/*worst case*/
                lat = SD_T_READ_WRITE_SROW;
                same_row_read_access++;
                srr_after_write++;
                worst_case++;
                  }
                else/*write*/
                  {/*worst case*/
                lat = SD_T_WRITE_READ_SROW;
                same_row_write_access++;
                srw_after_read++;
                worst_case++;
                  }
              }
            else /*other row in same bank*/   
              {
                if (current_cmd == Read)
                  {/*worst case*/
                lat = SD_T_READ_WRITE_SBANK;
                same_bank_read_access++;
                sbr_after_write++;
                worst_case++;
                  }
                else/*write*/
                  {		      
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if (corrected_overlap >= SD_T_PRE)/*best case*/
                      {
                    lat = SD_BEST_T_WRITE_READ_SBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_WRITE_READ_SBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = SD_T_WRITE_READ_OBANK;
                    worst_case++;
                  }
                same_bank_write_access++;
                sbw_after_read++;			
                  }
              }
              }
            else /*other bank*/
              {
            if (current_cmd == Read)
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { /*best case*/
                lat = SD_BEST_T_READ_WRITE_OBANK;
                best_case++;
                other_bank_read_access_hit++;
                obr_after_write_hit++;		  
                  }
                else/*row is not active*/
                  {
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >= (SD_T_PRE+SD_T_ACT))/*best case*/
                      {
                    lat = SD_BEST_T_READ_WRITE_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_READ_WRITE_OBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = SD_T_READ_WRITE_OBANK;
                    worst_case++;
                  }
                other_bank_read_access_miss++;
                obr_after_write_miss++;		  
                  }
              }
            else/*write*/
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { /*best case*/
                lat = SD_BEST_T_WRITE_READ_OBANK;
                best_case++;
                other_bank_write_access_hit++;
                obw_after_read_hit++;
                  }
                else/*row is not active*/
                  {
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if (corrected_overlap >= (SD_T_WRITE_READ_OBANK-SD_BEST_T_WRITE_READ_OBANK))/*best case*/
                      {/*best case*/
                    lat = SD_BEST_T_WRITE_READ_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = SD_T_WRITE_READ_OBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = SD_T_WRITE_READ_OBANK;
                    worst_case++;
                  }
                other_bank_write_access_miss++;
                obw_after_read_miss++;
                  }
              }
              }
          }
        /*fprintf(stderr,"%4d %4d ",lat,active_row[current_bank]);debugging*/

        lat += chunks; /* burst length added*/

        /*fprintf(stderr,"%4d ",lat);debugging*/

        active_row[current_bank]=current_row; /* open-page (hit) register */
        last_cmd  = current_cmd;
        last_bank = current_bank;
        last_row  = current_row;

        if (cpu_ratio < 1.0) 
          {
            lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
          }
        else 
          {
            temp = (int)(lat*cpu_ratio);      
            lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
          }

        /*fprintf(stderr,"%4d \n",lat);debugging*/

        if (overlap <= 0) /*memory interface is not busy*/
          {
            if (memctrlpipe_enable == TRUE) 
              {
              busy_until=now+lat;
              }
            else 
              {
            if (busy_until >= now) 
              {
                busy_until+=lat;
                lat=busy_until - now;
              }
            else busy_until=now+lat;
              }
          }
        else/*the memory request will be satisfied temp cycles after now*/
          {
            busy_until+=lat;
            command_overlapping++;
            lat+=overlap; 
          }
        return lat;
      }
    

    /***********************************************************/
    /********************     DRDRAM     ***********************/
    /***********************************************************/

    else if (!strcmp(mem_type,"DRDRAM") && !strcmp(mem_actpolicy, "open"))/*DRDRAM*/ /*a closed bank has an activ_row number of DR_NUM_ROWS: highest +1*/
      {
        if (strcmp(memctrladdr_type,"interleaved"))/* i.e. mc_type is linear */
          {
            current_bank=physic_address/DR_BANK_SIZE;
            temp=physic_address-current_bank*DR_BANK_SIZE;/*address in bank*/
            current_row=temp/DR_ROW_SIZE;
            current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
          }

        else/*mc_type interleaved*/
          /* This memory controller maps the addresses differently
           * depending on the row-size, every row is mapped to another
           * bank. So the text segment uses half of every bank. The heap
           * the next quarter of each bank and the stack the rest.
           */
          
          {
            num_blocks = physic_address/DR_ROW_SIZE; /* row number */
            current_bank=(num_blocks%DR_NUM_BANKS)*2; /*every 'second' bank will be used*/
            /*banks above DR_NUM_BANKS are the uneven banks*/
            current_bank = ((current_bank <  DR_NUM_BANKS) ? current_bank:(current_bank - DR_NUM_BANKS+1));
            current_row=num_blocks/DR_NUM_BANKS;
            current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
              }         
        if (abs(current_bank-last_bank)==1)/*access to an adjacent bank*/
          {
            if (!((current_bank%DR_BANK_SAMP == (DR_BANK_SAMP-1))&&(last_bank%DR_BANK_SAMP == 0))/*not 15/16 (current/last)*/
            &&(!((last_bank%DR_BANK_SAMP == (DR_BANK_SAMP-1))&&(current_bank%DR_BANK_SAMP == 0))))/*not 16/15(current/last)*/
              {
            adjacent_access++;
            adjacent=1;/*an adjacent bank is accessed*/
            if (cmd == Read)
              adjacent_read++;
            else
              adjacent_write++;
              }
          } 
        precharge=0;/*at this moment no bank needs to be precharged*/
        if (active_row[current_bank] == DR_NUM_ROWS)/*bank is precharged*/
          {
            if (precharge_banks_around(current_bank)> 0)/*a bank next to the current is activated*/
              {
            if ((adjacent==1)&&(precharge==1))
              {
                /*since adjacent banks share SAMPs, this access would be the same as (in terms of latency)  
                 *an access to another row in the same bank if only one adjacent bank was active*/
                last_bank = current_bank;
                last_row = current_row+1;
                precharge=0;/*set to 0 for next memory access*/
              }
              }
          }
        current_cmd = cmd;
        if (mem_access_output != NULL && mem_access_details == TRUE) 
          {
            fprintf(mem_accessfd,"       %09u  %4d   %3d  %15d\n",physic_address,current_row,current_bank,(int)adjacent_access);
          }
        else	    
          {
            if (mem_access_output!=NULL)
              {
            fprintf(mem_accessfd,"\n");
              }
          }
        total_access++;

        if (memctrlpipe_enable == TRUE) 
          {
            overlap=(int)(busy_until - now);
          }
        else overlap=0;

        if (cpu_ratio < 1.0)
          {
            corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
          }
        else
          {
            corrected_overlap = (int) (overlap/cpu_ratio);
          }

        /*fprintf(stderr,"%10.0f %10.0f %6d %6d %2d %2d ",(double)busy_until, (double)now, overlap, corrected_overlap,precharge,adjacent);debugging*/

        if (current_cmd == last_cmd)/*same command*/
          {
            if (current_bank == last_bank)/*same bank*/
              {
            if (current_row == last_row)/*same row*/
              {
                if (current_cmd == Read)
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    /*best case*/
                    if (corrected_overlap >= DR_T_READ_READ_SROW)
                      {
                    lat=DR_BEST_T_READ_READ_SROW;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_READ_READ_SROW-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else
                  {
                    /*worst case*/
                    lat = DR_T_READ_READ_SROW;
                    worst_case++;
                  }
                same_row_read_access++;
                srr_after_read++;
                  }
                else/*write, always retire the previous data*/
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    /*best case*/
                    if (corrected_overlap >= DR_T_OWR)
                      {
                    lat=DR_BEST_T_WRITE_WRITE_SROW;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_WRITE_WRITE_SROW-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else
                  {
                    /*worst case*/
                    lat = DR_T_WRITE_WRITE_SROW;
                    worst_case++;
                  }
                same_row_write_access++;
                srw_after_write++;
                  }
              }
            else /*other row in same bank*/   
              { 
                if (current_cmd == Read)
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    if (corrected_overlap >= DR_T_HELP)/*best case*/
                      {
                    lat = DR_BEST_T_READ_READ_SBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_READ_READ_SBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = DR_T_READ_READ_SBANK;
                    worst_case++;
                  }
                same_bank_read_access++;
                sbr_after_read++;
                  }
                else/*write*/
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    if (corrected_overlap >= DR_T_OWR)/*best case*/
                      {
                    lat = DR_BEST_T_WRITE_WRITE_SBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_WRITE_WRITE_SBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = DR_T_WRITE_WRITE_SBANK;
                    worst_case++;
                  }
                same_bank_write_access++;
                sbw_after_write++;
                  }
              }
              }
            else /*other bank*/
              {
            if (current_cmd == Read)
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { 
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >= (DR_T_CAC+DR_T_PACKET))/*best case*/
                      {
                    lat = DR_BEST_T_READ_READ_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_CAC+DR_T_PACKET-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*in between case*/
                  {
                    lat = DR_T_CAC+DR_T_PACKET;
                    in_between_case++;
                  }
                other_bank_read_access_hit++;
                obr_after_read_hit++;
                  }
                else/*row is not active or bank is precharged/not active*/
                  {
                if (active_row[current_bank]!=DR_NUM_ROWS)/*row is not active, but bank is active*/
                  {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                    if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET))/*best case*/
                      {
                        lat = DR_BEST_T_READ_READ_OBANK;
                        best_case++;
                        full_overlapping++;
                      }
                    else/*in between case*/
                      {
                        lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                      }
                      }
                    else/*worst case*/
                      {
                    lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET;
                    in_between_case++;
                      }
                  }
                else/*current_row == DR_NUM_ROWS:precharged or inactive*/
                  {
                    if(precharge == 0)/*no adjacent bank is active*/
                      {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                        if(corrected_overlap >= (DR_T_RCD+DR_T_CAC+DR_T_PACKET))/*best case*/
                          {
                        lat = DR_BEST_T_READ_READ_OBANK;
                        best_case++;
                        full_overlapping++;
                          }
                        else/*in between case*/
                          {
                        lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                          }
                      }
                    else/*worst case*/
                      {
                        lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET;
                        in_between_case++;
                      } 
                      }
                    else/*one ore two adjacent banks are active*/
                      {
                    if (precharge == 1)
                      {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                        if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET))/*best case*/
                          {
                            lat = DR_BEST_T_READ_READ_OBANK;
                            best_case++;
                            full_overlapping++;
                          }
                        else/*in between case*/
                          {
                            lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET)-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                          }
                          }
                        else/*worst case*/
                          {
                        lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET);
                        in_between_case++;
                          } 			    
                      }
                    else /*precharge ==2: two rows must be precharged*/
                      {
                        if (adjacent == 1)/*these banks are adjacent*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_PP+2*DR_T_PACKET-DR_T_RDP+DR_T_CAC)/*best case*/
                              {
                            lat = DR_T_RDP+DR_T_RP+DR_T_RCD-DR_T_PACKET;
                            in_between_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_READ_READ_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_READ_READ_OBANK;
                            worst_case++;
                          }
                          }
                        else/*adjacent == 0: two not adjacent banks need to be precharged*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_READ_READ_OBANK)/*best case*/
                              {
                            lat = DR_BEST_T_READ_READ_OBANK;
                            best_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_READ_READ_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_READ_READ_OBANK;
                            worst_case++;
                          }
                          }
                      }
                      }			      
                  }
                other_bank_read_access_miss++;
                obr_after_read_miss++;
                  }
              }
            else/*write*/
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { 
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >= (DR_T_CWD+DR_T_PACKET))/*best case*/
                      {
                    lat = DR_BEST_T_WRITE_WRITE_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_CWD+DR_T_PACKET-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = DR_T_CWD+DR_T_PACKET;
                    in_between_case++;
                  }			 
                other_bank_write_access_hit++;
                obw_after_write_hit++;
                  }
                else/*row is not active or bank is precharged/not active*/
                  {
                if (active_row[current_bank] != DR_NUM_ROWS)/*row is not active,but bank is active*/
                  { 		      
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                    if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                      {
                        lat = DR_BEST_T_WRITE_WRITE_OBANK;
                        best_case++;
                        full_overlapping++;
                      }
                    else/*in between case*/
                      {
                        lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                      }
                      }
                    else/*worst case*/
                      {
                    lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET;
                    in_between_case++;
                      }
                  }
                else/*current_row == DR_NUM_ROWS:precharged or inactive*/
                  {
                    if(precharge == 0)/*no adjacent bank is active*/
                      {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                        if(corrected_overlap >= (DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                          {
                        lat = DR_BEST_T_WRITE_WRITE_OBANK;
                        best_case++;
                        full_overlapping++;
                          }
                        else/*in between case*/
                          {
                        lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                          }
                      }
                    else/*worst case*/
                      {
                        lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET;
                        in_between_case++;
                      } 
                      }
                    else/*one ore two adjacent banks are active*/
                      {
                    if (precharge == 1)/*last_bank is no adjacent*/
                      {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                        if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                          {
                            lat = DR_BEST_T_WRITE_WRITE_OBANK;
                            best_case++;
                            full_overlapping++;
                          }
                        else/*in between case*/
                          {
                            lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET)-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                          }
                          }
                        else/*worst case*/
                          {
                        lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET);
                        in_between_case++;
                          } 			    
                      }
                    else /*precharge ==2: two rows have to be precharged*/
                      {
                        if (adjacent == 1)/*these banks are adjacent*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_OWR+DR_T_PP)/*best case*/
                              {
                            lat = DR_T_WRITE_WRITE_OBANK-DR_T_OWR-DR_T_PP;
                            in_between_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_WRITE_WRITE_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_WRITE_WRITE_OBANK;
                            worst_case++;
                          }
                          }
                        else/*adjacent == 0: two not adjacent banks need to be precharged*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_WRITE_WRITE_OBANK)/*best case*/
                              {
                            lat = DR_BEST_T_WRITE_WRITE_OBANK;
                            best_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_WRITE_WRITE_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_WRITE_WRITE_OBANK;
                            worst_case++;
                          }
                          }
                      }
                      }			      
                  }
                other_bank_write_access_miss++;
                obw_after_write_miss++;
                  }
              } 
              }
          }
        else /*current_cmd != last_cmd*/
          {
            if (current_bank == last_bank)/*same bank*/
              {
            if (current_row == last_row)/*same row*/
              {
                if (current_cmd == Read)
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    /*best case*/
                    if (corrected_overlap >= DR_T_OWR)
                      {
                    lat=DR_BEST_T_READ_WRITE_SROW;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_READ_WRITE_SROW-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else
                  {
                    /*worst case*/
                    lat = DR_T_READ_WRITE_SROW;
                    worst_case++;
                  }
                same_row_read_access++;
                srr_after_write++;
                  }
                else/*write*/
                  {
                if (corrected_overlap > 0)/*overlapping*/
                  {
                    /*best case*/
                    if (corrected_overlap >= DR_T_WRITE_READ_SROW)
                      {
                    lat=DR_BEST_T_WRITE_READ_SROW;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_WRITE_READ_SROW-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else
                  {
                    /*worst case*/
                    lat = DR_T_WRITE_READ_SROW;
                    worst_case++;
                  }
                same_row_write_access++;
                srw_after_read++;
                  }
              }
            else /*other row in same bank*/   
              {
                if (current_cmd == Read)
                  {
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if (corrected_overlap >= DR_T_OWR)/*best case*/
                      {
                    lat = DR_BEST_T_READ_WRITE_SBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_READ_WRITE_SBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = DR_T_READ_WRITE_SBANK;
                    worst_case++;
                  }
                same_bank_read_access++;
                sbr_after_write++;
                  }
                else/*write*/
                  {		      
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if (corrected_overlap >= DR_T_HELP)/*best case*/
                      {
                    lat = DR_BEST_T_WRITE_READ_SBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_WRITE_READ_SBANK-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*worst case*/
                  {
                    lat = DR_T_WRITE_READ_SBANK;
                    worst_case++;
                  }
                same_bank_write_access++;
                sbw_after_read++;
                  }
              }
              }
            else /*other bank*/
              {
            if (current_cmd == Read)
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { 
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(last_dev != current_device)
                      {
                    if(corrected_overlap >= DR_T_CWD+DR_T_PACKET)/*best case*/
                      {
                        lat = DR_BEST_T_READ_WRITE_ODEV;
                        best_case++;
                        full_overlapping++;
                      }
                    else/*in between case*/
                      {
                        lat = DR_T_CAC+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                      }
                      }
                    else /* same device */
                      {
                    if(corrected_overlap >= DR_T_OWR)/*best case*/
                      {
                        lat = DR_BEST_T_READ_WRITE_OBANK;
                        best_case++;
                        full_overlapping++;
                      }
                    else/*in between case*/
                      {
                        lat = DR_T_CAC+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                      }
                      }
                      }
                else/*in between case, no overlap*/
                  {
                    lat = DR_T_CAC+DR_T_PACKET;
                    in_between_case++;
                  }
                other_bank_read_access_hit++;
                obr_after_write_hit++;		  
                  }

                else/*row is not active or bank is precharged/not active*/
                  {
                if (active_row[current_bank] != DR_NUM_ROWS)/*row is not active,but bank is active*/
                  {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                    if (last_dev != current_device)
                      {
                        if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                          {
                        lat = DR_BEST_T_READ_WRITE_ODEV;
                        best_case++;
                        full_overlapping++;
                          }
                        else/*in between case*/
                          {
                        lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                          }
                      }
                    else /* same device */
                      {
                        if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_OWR))/*best case*/
                          {
                        lat = DR_BEST_T_READ_WRITE_OBANK;
                        best_case++;
                        full_overlapping++;
                          }
                        else/*in between case*/
                          {
                        lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                          }
                      }
                      }
                    else/*worst case*/
                      {
                    lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET;
                    in_between_case++;
                      }
                  }
                else/*current_row == DR_NUM_ROWS:precharged or inactive*/
                  {
                    if(precharge == 0)/*no adjacent bank is active*/
                      {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                        if(last_dev != current_device)
                          {
                        if(corrected_overlap >= (DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                          {
                            lat = DR_BEST_T_READ_WRITE_ODEV;
                            best_case++;
                            full_overlapping++;
                          }
                        else/*in between case*/
                          {
                            lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                          }
                          }
                        else /* same device */
                          {
                        if(corrected_overlap >= (DR_T_RCD+DR_T_OWR))/*best case*/
                          {
                            lat = DR_BEST_T_READ_WRITE_OBANK;
                            best_case++;
                            full_overlapping++;
                          }
                        else/*in between case*/
                          {
                            lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                          }
                          }
                      }
                    else/*worst case*/
                      {
                        lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET;
                        in_between_case++;
                      } 
                      }
                    else/*one or two adjacent banks are active*/
                      {
                    if (precharge == 1)/*an adjacent bank (!=last_bank) needs to be precharged*/
                      {					  
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                        if(last_dev != current_device)
                          {
                            if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                              {
                            lat = DR_BEST_T_READ_WRITE_ODEV;
                            best_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET)-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else /* same device */
                          {
                            if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_OWR))/*best case*/
                              {
                            lat = DR_BEST_T_READ_WRITE_OBANK;
                            best_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET)-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                          }
                        else/*worst case*/
                          {
                        lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET);
                        in_between_case++;
                          } 			    
                      }
                    else /*precharge ==2: two rows have to be precharged*/
                      {
                        if (adjacent == 1) /* the banks are adjacent */
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_OWR + DR_T_PP)/*best case*/
                              {
                            lat = DR_T_READ_WRITE_OBANK-DR_T_OWR - DR_T_PP;
                            in_between_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_READ_WRITE_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_READ_WRITE_OBANK;
                            worst_case++;
                          }
                          }
                        else/*adjacent == 0: two not adjacent banks need to be precharged*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if (last_dev != current_device)
                              {
                            if(corrected_overlap >= (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                              {
                                lat = DR_BEST_T_READ_WRITE_ODEV;
                                best_case++;
                                full_overlapping++;
                              }
                            else/*in between case*/
                              {
                                lat = DR_T_READ_WRITE_OBANK-corrected_overlap;
                                in_between_case++;
                                partial_overlapping++;
                              }
                              }
                            else /* same device */
                              {
                            if(corrected_overlap >= (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_OWR))/*best case*/
                              {
                                lat = DR_BEST_T_READ_WRITE_OBANK;
                                best_case++;
                                full_overlapping++;
                              }
                            else/*in between case*/
                              {
                                lat = DR_T_READ_WRITE_OBANK-corrected_overlap;
                                in_between_case++;
                                partial_overlapping++;
                              }
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_READ_WRITE_OBANK;
                            worst_case++;
                          }
                          }
                      }
                      }			      
                  }
                other_bank_read_access_miss++;
                obr_after_write_miss++;		  
                  }
              }
            else/*write*/
              {
                if (current_row == active_row[current_bank])/*row is still active*/
                  { 
                if (corrected_overlap > 0 )/*overlapping*/
                  {
                    if(corrected_overlap >= DR_T_CWD+DR_T_PACKET)/*best case*/
                      {
                    lat = DR_BEST_T_WRITE_READ_OBANK;
                    best_case++;
                    full_overlapping++;
                      }
                    else/*in between case*/
                      {
                    lat = DR_T_CWD+DR_T_PACKET-corrected_overlap;
                    in_between_case++;
                    partial_overlapping++;
                      }
                  }
                else/*in between case*/
                  {
                    lat = DR_T_CWD+DR_T_PACKET;
                    in_between_case++;
                  }
                other_bank_write_access_hit++;
                obw_after_read_hit++;		  
                  }
                else/*row is not active or bank is precharged/not active*/
                  {
                if (active_row[current_bank] != DR_NUM_ROWS)/*row is not active,but bank is active*/
                  {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                    if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                      {
                        lat = DR_BEST_T_WRITE_READ_OBANK;
                        best_case++;
                        full_overlapping++;
                      }
                    else/*in between case*/
                      {
                        lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                      }
                      }
                    else/*worst case*/
                      {
                    lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET;
                    in_between_case++;
                      }
                  }
                else/*current_row == DR_NUM_ROWS:precharged or inactive*/
                  {
                    if(precharge == 0)/*no adjacent bank is active*/
                      {
                    if (corrected_overlap > 0 )/*overlapping*/
                      {
                        if(corrected_overlap >= (DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                          {
                        lat = DR_BEST_T_WRITE_READ_OBANK;
                        best_case++;
                        full_overlapping++;
                          }
                        else/*in between case*/
                          {
                        lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
                        in_between_case++;
                        partial_overlapping++;
                          }
                      }
                    else/*worst case*/
                      {
                        lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET;
                        in_between_case++;
                      } 
                      }
                    else/*one or two adjacent banks are active*/
                      {
                    if (precharge == 1)/*an adjacent bank (!=last_bank)  needs to be precharged first*/
                      {					  
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                        if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
                          {
                            lat = DR_BEST_T_WRITE_READ_OBANK;
                            best_case++;
                            full_overlapping++;
                          }
                        else/*in between case*/
                          {
                            lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET)-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                          }
                          }
                        else/*worst case*/
                          {
                        lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET);
                        in_between_case++;
                          } 			    
                      }
                    else /*precharge ==2: two rows have to be precharged*/
                      {
                        if (adjacent == 1)/*these banks are adjacent*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_PP-DR_T_RDP+2*DR_T_PACKET+DR_T_CAC)/*best case*/
                              {
                            lat = DR_T_WRITE_READ_OBANK-(DR_T_PP-DR_T_RDP+2*DR_T_PACKET+DR_T_CAC);
                            in_between_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_WRITE_READ_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_WRITE_READ_OBANK;
                            worst_case++;
                          }
                          }
                        else/*adjacent == 0: two not adjacent banks need to be precharged*/
                          {
                        if (corrected_overlap > 0 )/*overlapping*/
                          {
                            if(corrected_overlap >= DR_T_WRITE_READ_OBANK)/*best case*/
                              {
                            lat = DR_BEST_T_WRITE_READ_OBANK;
                            best_case++;
                            full_overlapping++;
                              }
                            else/*in between case*/
                              {
                            lat = DR_T_WRITE_READ_OBANK-corrected_overlap;
                            in_between_case++;
                            partial_overlapping++;
                              }
                          }
                        else/*worst case*/
                          {
                            lat = DR_T_WRITE_READ_OBANK;
                            worst_case++;
                          }
                          }
                      }
                      }			      
                  }
                other_bank_write_access_miss++;
                obw_after_read_miss++;		  
                  }
              }
              }
          }
        /*fprintf(stderr,"%4d %4d ",lat,active_row[current_bank]);debugging*/

        lat += chunks * DR_T_PACKET; /*every 128 bit need DR_NUM_CYCLES*/

        /*fprintf(stderr,"%4d ",lat);debugging*/

        if (cpu_ratio < 1.0) 
          {
            lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
          }
        else 
          {
            temp = (int)(lat*cpu_ratio);      
            lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
          }

        active_row[current_bank]=current_row;
        last_cmd=current_cmd;
        last_bank=current_bank;
        last_row = current_row;
        last_dev = current_device;

        /*fprintf(stderr,"%4d \n",lat);debugging*/

        if (overlap <= 0) /*memory interface is not busy*/
          {
            if (memctrlpipe_enable == TRUE) 
              {
            busy_until=now+lat;
              }
            else 
              {
            if (busy_until >= now) 
              {
                busy_until+=lat;
                lat=busy_until - now;
              }
            else busy_until=now+lat;		
              }
          }
        else/*the memory request will be satisfied temp cycles after now*/
          {
            busy_until+=lat;
            command_overlapping++;
            lat+=overlap; 
          }
        return lat;
      }

        /******************************************************************/

    else if (!strcmp(mem_type,"SDRAM") && !strcmp(mem_actpolicy, "closed") && (memctrlpipe_enable == TRUE))
       /* SDRAM closed-page with overlap, 2/00 MG */
      {
        if (strcmp(memctrladdr_type,"interleaved"))/* i.e. mc_type is linear*/
          {
            current_bank=physic_address/SD_BANK_SIZE;
          }
        else/*mc_type interleaved*/
          /* This memory management unit maps the addresses different
           * depending on the row_size, every row is mapped to another
           * bank. So the text segment uses half of every bank. The heap
           * the next quarter of each bank and the stack the rest.
           */
              {
            num_blocks = physic_address/SD_ROW_SIZE; /* row number */
            current_bank=num_blocks%SD_NUM_BANKS; 
          }

        current_cmd = cmd;
        if (mem_access_output != NULL && mem_access_details == TRUE) 
          {
            fprintf(mem_accessfd,"       %09u   %3d\n",physic_address,current_bank);
          }
        else	    
          {
            if (mem_access_output!=NULL)
              {
            fprintf(mem_accessfd,"\n");
              }
          }
        total_access++;

        overlap=(int)(busy_until - now);

        if (current_bank == last_bank)/*same bank*/
          {
            if ((current_cmd == last_cmd) && (current_cmd == Read))/* RAR */
              {
            lat = SD_T_ACT + SD_T_CAS;
              }
            else if ((current_cmd == last_cmd) && (current_cmd == Write)) /* WAW */
              {
            lat = SD_T_ACT;
              }
            else if ((current_cmd != last_cmd) && (current_cmd == Read)) /* RAW */
              { 
            lat = SD_T_ACT + SD_T_CAS;
              }
            else /* WAR */
              {
            lat = SD_T_ACT;
              }
          }
        else /* other bank */
          {
            if (cpu_ratio < 1.0)
              {
            corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
              }
            else
              {
            corrected_overlap = (int) (overlap/cpu_ratio);
              }

            if ((current_cmd == last_cmd) && (current_cmd == Read))/* RAR */
              {
            if (corrected_overlap > SD_T_ACT + SD_T_CAS) 
              {
                lat = 0;
                best_case++;
                full_overlapping++;
              }
            else if (corrected_overlap > 0) 
              {
                lat = SD_T_ACT + SD_T_CAS - corrected_overlap;
                in_between_case++;
                partial_overlapping++;
              }
            else 
              {
                lat = SD_T_ACT + SD_T_CAS;
                worst_case++;
              }
              }
            else if ((current_cmd == last_cmd) && (current_cmd == Write)) /* WAW */
              {
            if (corrected_overlap > SD_T_ACT + SD_T_PRE + (SD_T_DPL-1)) 
              {
                lat = - SD_T_PRE - SD_T_DPL +1;
                best_case++;
                full_overlapping++;
              }
            else if (corrected_overlap > 0) 
              {
                lat = SD_T_ACT - corrected_overlap;
                in_between_case++;
                partial_overlapping++;
              }
            else 
              {
                lat = SD_T_ACT;
                worst_case++;
              }
              }
            else if ((current_cmd != last_cmd) && (current_cmd == Read)) /* RAW */
              { 
            if (corrected_overlap > SD_T_CAS + SD_T_PRE + SD_T_DPL - 1 ) 
              {
                lat = SD_T_ACT - (SD_T_PRE + SD_T_DPL - 1);
                best_case++;
                partial_overlapping++;
              }
            else if (corrected_overlap > 0) 
              {
                lat = SD_T_ACT + SD_T_CAS - corrected_overlap;
                in_between_case++;
                partial_overlapping++;
              }
            else 
              {
                lat = SD_T_ACT + SD_T_CAS;
                worst_case++;
              }
              }
            else /* WAR */
              {
            if (corrected_overlap > SD_T_ACT - (SD_T_DPL-1)) 
              {
                lat = SD_T_DPL-1;
                best_case++;
                partial_overlapping++;
              }
            else if (corrected_overlap > 0) 
              {
                lat = SD_T_ACT - corrected_overlap;
                in_between_case++;
                partial_overlapping++;
              }
            else 
              {
                lat = SD_T_ACT;
                worst_case++;
              }
              }
          }

        last_cmd=current_cmd;
        last_bank=current_bank;
        last_row = current_row;

        lat += chunks;
        
        if (cpu_ratio < 1.0) 
          {
            lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
          }
        else 
          {
            temp = (int)(lat*cpu_ratio);      
            lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
          }

        /*fprintf(stderr,"%4d \n",lat); debugging */

        if (overlap <= 0) /*memory interface is not busy*/
          {
            busy_until=now+lat;
          }
        else /*the memory request will be satisfied temp cycles after now*/
          {
            busy_until+=lat;
            command_overlapping++;
            lat+=overlap; 
          }
        if (current_cmd == Write) 
          {
           temp = (int)(((SD_T_DPL-1) + SD_T_PRE)*cpu_ratio);
           busy_until += (((SD_T_DPL-1) + SD_T_PRE)*cpu_ratio == temp)?temp:(temp+1);
          }

        /*fprintf(stderr,"%10.0f %10.0f %4d %4d \n",(double)busy_until, (double)now, overlap, lat);debug*/
        return lat;
      }    
	  
    /******************************************************************/

    else if (!strcmp(mem_type,"DRDRAM") && !strcmp(mem_actpolicy, "closed") && (memctrlpipe_enable == TRUE)) 
      /* DRDRAM closed-page with overlap*/
     {

	if (strcmp(memctrladdr_type,"interleaved"))/*i.e. mc_type is linear*/
	  {
	    current_bank=physic_address/DR_BANK_SIZE;
	    current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
	  }
	else/*mc_type interleaved*/
	  /* This memory management unit maps the addresses different
	   * depending on the row-size, every row is mapped to another
	   * bank. So the text segment uses half of every bank. The heap
	   * the next quarter of each bank and the stack the rest.
	   */
     	  {
	    num_blocks = physic_address/DR_ROW_SIZE; /* row number */
	    current_bank=(num_blocks%DR_NUM_BANKS)*2; /*every 'second' bank will be used*/
	    /*banks above DR_NUM_BANKS are the uneven banks*/
	    current_bank = ((current_bank <  DR_NUM_BANKS) ? current_bank:(current_bank - DR_NUM_BANKS+1));
	    current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
	  }         

	current_cmd = cmd;

	if (mem_access_output != NULL && mem_access_details == TRUE) 
	  {
	    fprintf(mem_accessfd,"       %09u   %3d  \n",physic_address,current_bank);
	  }
	else	    
	  {
	    if (mem_access_output!=NULL)
	      {
		fprintf(mem_accessfd,"\n");
	      }
	  }
	total_access++;

	overlap=(int)(busy_until - now);

	if (cpu_ratio < 1.0)
	  {
	    corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
	  }
	else
	  {
	    corrected_overlap = (int) (overlap/cpu_ratio);
	  }

	if (current_bank == last_bank)/*same bank*/
	  {
	    if ((current_cmd == last_cmd) && (current_cmd == Read))/* RAR */
	      {
		lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
		worst_case++;
       	      }
	    else if ((current_cmd == last_cmd) && (current_cmd == Write)) /* WAW */
	      {
		lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
		worst_case++;
	      }
	    else if ((current_cmd != last_cmd) && (current_cmd == Read)) /* RAW */
	      { 
		lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
		worst_case++;
	      }
	    else /* WAR */
	      {
		lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
		worst_case++;
	      }
	  }
	else /* other bank */
	  {
	    if ((current_cmd == last_cmd) && (current_cmd == Read))/* RAR */
	      {
		if (corrected_overlap > DR_T_RAS + DR_T_RP - 2 * DR_T_PACKET) 
		  {
		    lat = - DR_T_RAS + DR_T_RCD + DR_T_PACKET + DR_T_CAC;
		    best_case++;
		    full_overlapping++;
		  }
		else if (corrected_overlap > 0) 
		  {
		    lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET - corrected_overlap;
		    in_between_case++;
		    partial_overlapping++;
		  }
		else 
		  {
		    lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
		    worst_case++;
		  }
	      }
	    else if ((current_cmd == last_cmd) && (current_cmd == Write)) /* WAW */
	      {
		if (corrected_overlap > DR_T_RCD + DR_T_RTR  + DR_T_RP) 
		  {
		    lat = - DR_T_CWD - 2 * DR_T_PACKET + DR_T_RTR;
		    best_case++;
		    full_overlapping++;
		  }
		else if (corrected_overlap > 0) 
		  {
		    lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET - corrected_overlap;
		    in_between_case++;
		    partial_overlapping++;
		  }
		else 
		  {
		    lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
		    worst_case++;
		  }
	      }
	    else if ((current_cmd != last_cmd) && (current_cmd == Read)) /* RAW */
	      { 
		if (current_device == last_dev) /* same device */
		  {
		    if (corrected_overlap >  DR_T_RCD + DR_T_RP) 
		      {
			lat = DR_T_PACKET + DR_T_CAC - DR_T_RP;
			best_case++;
			partial_overlapping++;
		      }
		    else if (corrected_overlap > 0) 
		      {
			lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET - corrected_overlap;
			in_between_case++;
			partial_overlapping++;
		      }
		    else 
		      {
			lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
			worst_case++;
		      }
		  }
		else /* other device */
		  {
		    if (corrected_overlap > DR_T_RCD + DR_T_RP + 2 * DR_T_PACKET) 
		      {
			lat = - DR_T_PACKET + DR_T_CAC - DR_T_RP;
			best_case++;
			partial_overlapping++;
		      }
		    else if (corrected_overlap > 0) 
		      {
			lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET - corrected_overlap;
			in_between_case++;
			partial_overlapping++;
		      }
		    else 
		      {
			lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
			worst_case++;
		      }
		  }
	      }
	    else /* WAR */
	      {
		if (corrected_overlap > DR_T_RAS + DR_T_RP - 2 * DR_T_PACKET - (DR_T_CAC - DR_T_CWD)) 
		  {
		    lat = - DR_T_RAS + DR_T_RCD + DR_T_PACKET + DR_T_CAC;
		    best_case++;
		    full_overlapping++;
		  }
		else if (corrected_overlap > 0) 
		  {
		    lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET - corrected_overlap;
		    in_between_case++;
		    partial_overlapping++;
		  }
		else 
		  {
		    lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
		    worst_case++;
		  }
	      }
	  }

	lat += chunks * DR_T_PACKET; /*every 128 bit need DR_NUM_CYCLES*/
	
	/*fprintf(stderr,"%4d ",lat);debugging*/

	if (cpu_ratio < 1.0) 
	  {
	    lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
	  }
	else 
	  {
	    temp = (int)(lat*cpu_ratio);      
	    lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
	  }

	last_cmd=current_cmd;
	last_bank=current_bank;
	last_dev = current_device;
	
	/*fprintf(stderr,"%4d \n",lat);debugging*/

	if (overlap <= 0) /*memory interface is not busy*/
	  {
	    busy_until=now+lat;
	  }
	else/*the memory request will be satisfied temp cycles after now*/
	  {
	    busy_until+=lat;
	    command_overlapping++;
	    lat+=overlap; 
	  }

	/*fprintf(stderr,"%10.0f %10.0f %4d %4d \n",(double)busy_until, (double)now, overlap, lat);*/

	if (current_cmd == Read)
	  {
	    if (cpu_ratio < 1.0)
	      {
		busy_until += abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
	      }
	    else
	      {
		busy_until += (int) abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)*cpu_ratio); /* CPU clock cycles */
	      }
	  }
	 else /* current_cmd == Write */
	  {
	    if (cpu_ratio < 1.0)
	      {
		busy_until += abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
	      }
	    else
	      {
		busy_until += (int) abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)*cpu_ratio); /* CPU clock cycles */
	      }
	  }
	return lat;
      }

    /******************************************************************/

    else if (!strcmp(mem_type,"SDRAM") && !strcmp(mem_actpolicy, "closed") && (memctrlpipe_enable == FALSE))
      /* SDRAM closed-page without overlap, 7/99 MG */
      {
	if (mem_access_output != NULL)
	  {
	    fprintf(mem_accessfd,"\n"); 
	  }
	assert(chunks >0);
	
 	if (current_cmd == Read)
	  {
	    lat = SD_T_ACT + SD_T_CAS;
	  }
	else /* current_cmd == Write */
	  {
	    lat = SD_T_ACT;
	  }
	total_access++;
	lat += chunks;
	
	overlap=(int)(busy_until - now);
	last_cmd=current_cmd;

	if (cpu_ratio < 1.0) 
	  {
	    lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
	  }
	else 
	  {
	    temp = (int)(lat*cpu_ratio);      
	    lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
	  }

	if (overlap <= 0) /*memory interface is not busy*/
	  {
	    busy_until=now+lat;
	  }
	else/*the memory request will be satisfied temp cycles after now*/
	  {
	    busy_until+=lat;
	    command_overlapping++;
	    lat+=overlap; 
	  }
	if (current_cmd == Write) 
	  {
	    temp = (int)(((SD_T_DPL-1) + SD_T_PRE)*cpu_ratio);
	    busy_until += (((SD_T_DPL-1) + SD_T_PRE)*cpu_ratio == temp)?temp:(temp+1);
	  }
	return lat;
      }    
	  
    /******************************************************************/

    else if (!strcmp(mem_type,"DRDRAM") && !strcmp(mem_actpolicy, "closed") && (memctrlpipe_enable == FALSE))
      /* DRDRAM closed-page without overlap */
      {
	if (current_cmd == Read)
	  {
	    lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET; /*  DR_T_RP + */
	  }
	else /* current_cmd == Write */
	  {
	    lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET; /* DR_T_RP + */
	  }
	total_access++;
	overlap=(int)(busy_until - now);
	lat += chunks * DR_T_PACKET; /*every 128 bit need DR_NUM_CYCLES*/
	
	if (cpu_ratio < 1.0) 
	  {
	    lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
	  }
	else 
	  {
	    temp = (int)(lat*cpu_ratio);      
	    lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
	  }

	last_cmd=current_cmd;
	
	if (overlap <= 0) /*memory interface is not busy*/
	  {
	    busy_until=now+lat;
	  }
	else/*the memory request will be satisfied temp cycles after now*/
	  {
	    busy_until+=lat;
	    command_overlapping++;
	    lat+=overlap; 
	  }

	if (current_cmd == Read)
	  {
	    if (cpu_ratio < 1.0) 
	      {
		busy_until += abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
	      }
	    else
	      {
		busy_until += (int) abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)*cpu_ratio); /* CPU clock cycles */
	      }		
	  }
	 else /* current_cmd == Write */
	  {
	    if (cpu_ratio < 1.0)
	      {
		busy_until += abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
	      }
	    else
	      {
		busy_until += (int) abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)*cpu_ratio); /* CPU clock cycles */
	      }
	  }
	return lat;
      }

    /******************************************************************/

    else /*STD*/
      {
	if (mem_access_output != NULL)
	  {
	    fprintf(mem_accessfd,"\n"); 
	  }
	assert(chunks >0);
	return(/* first chunk latency */mem_lat[0] +
	       (/* remainder chunk latency */mem_lat[1] * (chunks - 1)));
      }
    
}


